package com.xmall.utils;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xmall.define.base.BaseRetryLog;
import com.xmall.define.constants.CommonProperties;
import com.xmall.define.dict.LogStatusEnum;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.function.Consumer;

@Component
public class TimerUtils {

    /**
     * 日志重试
     */
    public static <T extends BaseRetryLog> void retryExecute(CommonProperties commonProperties, IService<T> service, Consumer<T> consumer) {
        TimerUtils.nextRetryLogList(commonProperties, service).forEach(retryLog -> {
            try {
                consumer.accept(retryLog);
            }catch (Exception e) {
                retryLog.setException(e.getMessage());
                service.updateById(TimerUtils.buildNextRetryInfo(commonProperties, retryLog));
            }
        });
    }

    /**
     * 获取需要重试的日志列表
     */
    private static <T extends BaseRetryLog> List<T> nextRetryLogList(CommonProperties commonProperties, IService<T> service) {
        return service.list(new QueryWrapper<T>()
            .lt("retry_count", commonProperties.getLogRetryIntervalSecondsList().size())
            .le("next_retry_time", new Date())
            .eq("log_status", LogStatusEnum.PROCESSING.getStatus()));
    }

    /**
     * 设置下一次重试信息
     */
    private static <T extends BaseRetryLog> T buildNextRetryInfo(CommonProperties commonProperties, T retryLog) {
        retryLog.setRetryCount(retryLog.getRetryCount() + 1);
        retryLog.setNextRetryTime(TimerUtils.nextRetryTime(commonProperties, retryLog.getNextRetryTime(), retryLog.getRetryCount()));
        return retryLog;
    }

    /**
     * 获取下一次重试的时间
     */
    private static Date nextRetryTime(CommonProperties commonProperties, Date prevRetryTime, Integer currentRetryCount) {
        if(currentRetryCount < commonProperties.getLogRetryIntervalSecondsList().size()) {
            return DateUtil.offsetSecond(prevRetryTime, commonProperties.getLogRetryIntervalSecondsList().get(currentRetryCount));
        }
        return null;
    }
}
